package com.zzxx.wechat.util;

import com.zzxx.wechat.common.BrdProxyProperty;
import com.alibaba.fastjson.JSON;
import com.zzxx.wechat.exception.BusinessException;
import lombok.extern.slf4j.Slf4j;
import org.apache.http.*;
import org.apache.http.auth.AuthScope;
import org.apache.http.auth.UsernamePasswordCredentials;
import org.apache.http.client.CredentialsProvider;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.BasicCredentialsProvider;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.impl.conn.DefaultProxyRoutePlanner;
import org.apache.http.ssl.SSLContextBuilder;
import org.apache.http.util.EntityUtils;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import javax.net.ssl.SSLContext;
import java.io.*;
import java.net.MalformedURLException;
import java.net.URL;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.security.*;
import java.util.ArrayList;
import java.util.List;
import java.util.Properties;

@Component
@Slf4j
public class HttpProxyClient {

    @Resource
    private BrdProxyProperty brdProxyProperty;


//    public static final String BRD_PROXY_HOST = "brd.superproxy.io";
//    public static final int BRD_PROXY_PORT = 33335;
//    public static final String BRD_PROXY_USER = "brd-customer-hl_b3246fe5-zone-residential_proxy1-country-jp";
//    public static final String BRD_PROXY_PASSWORD = "n62p45lthsqb";

    public static BrdProxyProperty loadFromDisk(String filePath) throws Exception {
        Properties props = new Properties();

        // 从磁盘路径读取文件
        try (InputStream is = Files.newInputStream(Paths.get(filePath))) {
            props.load(is);
        }

        BrdProxyProperty property = new BrdProxyProperty();
        property.setHost(props.getProperty("host"));
        property.setPort(Integer.parseInt(props.getProperty("port")));
        property.setUser(props.getProperty("user"));
        property.setPassword(props.getProperty("password"));

        return property;
    }


    /**
     * 创建自定义的 SSL 上下文，用于绕过证书验证
     */
    private  CloseableHttpClient createSSLIgnoreHttpClient() {
        try {
/*
            // 信任所有证书
            SSLContext sslContext = new SSLContextBuilder().loadTrustMaterial(null, (arg0, arg1) -> true).build();
            // 创建主机名验证器，用于绕过主机名验证
            HostnameVerifier hostnameVerifier = NoopHostnameVerifier.INSTANCE;
            // 创建 SSL 连接套接字工厂，将自定义的 SSL 上下文和主机名验证器应用于 HTTPS 连接
            SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(sslContext, hostnameVerifier);
*/
            // 设置代理及认证信息
            DefaultProxyRoutePlanner routePlanner = new DefaultProxyRoutePlanner(
                    new HttpHost(brdProxyProperty.getHost(), brdProxyProperty.getPort()));

            CredentialsProvider credentialsProvider = new BasicCredentialsProvider();
            credentialsProvider.setCredentials(
                    new AuthScope(brdProxyProperty.getHost(), brdProxyProperty.getPort()),
                    new UsernamePasswordCredentials(brdProxyProperty.getUser(), brdProxyProperty.getPassword()));
            // 信任所有证书
            SSLContext sslContext = new SSLContextBuilder().loadTrustMaterial(null, (chain, authType) -> true).build();
            // 创建 SSL 连接套接字工厂，将自定义的 SSL 上下文和主机名验证器应用于 HTTPS 连接
            SSLConnectionSocketFactory sslFactory = new SSLConnectionSocketFactory(sslContext);


            // 创建自定义的 CloseableHttpClient 实例，将 SSL 连接套接字工厂应用于 HTTP 客户端
            RequestConfig requestConfig = RequestConfig.custom()
                    .setConnectTimeout(10000)
                    .setSocketTimeout(30000)
                    .build();
            return HttpClients.custom()
                    .setRoutePlanner(routePlanner)
                    .setDefaultCredentialsProvider(credentialsProvider)
                    .setSSLSocketFactory(sslFactory)
                    .setDefaultRequestConfig(requestConfig)
                    .build();
        } catch (KeyManagementException | NoSuchAlgorithmException | KeyStoreException e) {
            log.error("创建SSL客户端失败", e);
            return null;
        }
    }


    /**
     * GET 请求
     */
    public  String doGetIgnoreSsl(String url) {
        return doGetIgnoreSsl(createSSLIgnoreHttpClient(), url);
    }

    public  String doGetIgnoreSsl(CloseableHttpClient httpclient, String url) {

        HttpGet request = new HttpGet(url);
        request.setHeader("User-Agent", "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/109.0.0.0 Safari/537.36");
        // request.setHeader("Referer", queryProtocolAndDomain(url));
        //   request.setHeader("Accept", "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9");

        try (CloseableHttpResponse response = httpclient.execute(request)) {
            int statusCode = response.getStatusLine().getStatusCode();
            System.out.println("Response Status Code: " + statusCode);

            if (statusCode == 200) {
                HttpEntity entity = response.getEntity();
                if (entity != null) {
                    return EntityUtils.toString(entity);
                }
                return null;
            } else {
                HttpEntity entity = response.getEntity();

                log.error("GET request failed with status code: {},err-code:{},err:{},errMessage:{}", statusCode,
                        queryResponseHeader("x-brd-err-code", response), queryResponseHeader("x-brd-error", response),
                        queryResponseHeader("x-brd-err-msg", response));
                throw new BusinessException("GET request failed with status code: " + statusCode);
            }
        } catch (IOException e) {
            throw new BusinessException(e);
        }

    }

    private  String queryResponseHeader(String s, CloseableHttpResponse response) {
        for (Header header : response.getAllHeaders()) {
            String name = header.getName();
            String value = header.getValue();

            if (name.equals(s)) {
                return value;
            }
        }
        return null;
    }

    private static String queryProtocolAndDomain(String url) {
        try {
            URL arcteryxUrl = new URL(url);
            return arcteryxUrl.getProtocol() + "://" + arcteryxUrl.getHost() + "/";
        } catch (MalformedURLException e) {
            throw new BusinessException("链接输入有误，请重新输入");
        }
    }


    /**
     * POST 请求
     */
    public  String doPostIgnoreSsl(String url, String params) throws Exception {
        return doPostIgnoreSsl(createSSLIgnoreHttpClient(), url, params);
    }


    public  String doPostIgnoreSsl(CloseableHttpClient httpclient, String url, String params) throws Exception {

        HttpPost httpPost = new HttpPost(url);// 创建httpPost
        httpPost.setHeader("Accept", "application/json");
        httpPost.setHeader("Content-Type", "application/json");
        String charSet = "UTF-8";
        StringEntity entity = new StringEntity(params, charSet);
        httpPost.setEntity(entity);
        CloseableHttpResponse response = null;
        try {
            response = httpclient.execute(httpPost);
            StatusLine status = response.getStatusLine();
            int state = status.getStatusCode();
            if (state == HttpStatus.SC_OK) {
                HttpEntity responseEntity = response.getEntity();
                return EntityUtils.toString(responseEntity);
            } else {
                log.error("POST request failed with status code: {}, url: {}", response.getStatusLine().getStatusCode(), url);
            }
        } finally {
            if (response != null) {
                try {
                    response.close();
                } catch (IOException e) {
                    log.error("response close failed, url: {}, param: {}", url, JSON.toJSONString(params), e);
                }
            }
            if (httpclient != null) {
                try {
                    httpclient.close();
                } catch (IOException e) {
                    log.error("httpclient close failed, url: {}, param: {}", url, JSON.toJSONString(params), e);
                }
            }
        }
        return null;

    }
}
